#include "hcpp/ptp2_log.h"
#include "hcpp/ptp2_default.h"

//#include "packet/packet.h"

//#include "hal/interval_timer_hal.h"
//#include "hal/critical_section.h"

#include <stdbool.h>
#include <stdio.h>
#include <time.h>
#include <inttypes.h>
#include <math.h>

// remove c99 warning implicit declaration (you can use gnu99 instead)
extern int snprintf(char *str, size_t size, const char *format, ...);

bool ptp2_log = false;

const char    *ptp2_log_empty_str = "";


typedef struct ptp2_log_date_t      ptp2_log_date_t;
struct ptp2_log_date_t {
    uint8_t     msec;
    uint8_t     sec;
    uint8_t     min;
    uint8_t     hour;
    uint8_t     day;
};

static void num2hexstr(uint32_t num, uint8_t *chr, size_t len);

ptp2_log_level_t PTP2_LOG_CATEGORY_LEVEL[] = {
    [PTP2_LOG_MASTER]                   = PTP2_LOG_ERROR,
    [PTP2_LOG_LOG]                      = PTP2_LOG_ERROR,
    [PTP2_LOG_HAL_ENET]                 = PTP2_LOG_ERROR,
    [PTP2_LOG_HAL_TIMER]                = PTP2_LOG_ERROR,
    [PTP2_LOG_HAL_PTP_TIME]             = PTP2_LOG_ERROR,
    [PTP2_LOG_HAL_SLAVEMGM]             = PTP2_LOG_ERROR,
    [PTP2_LOG_HAL_SYSCONF]              = PTP2_LOG_ERROR,
    [PTP2_LOG_HAL_TOD]                  = PTP2_LOG_ERROR,
    [PTP2_LOG_HAL_ESMC]                 = PTP2_LOG_ERROR,
    [PTP2_LOG_FSM]                      = PTP2_LOG_ERROR,
    [PTP2_LOG_PORT]                     = PTP2_LOG_ERROR,
    [PTP2_LOG_TASK]                     = PTP2_LOG_ERROR,
    [PTP2_LOG_TASK_QUEUE]               = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_ETHERNET]          = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_ARP]               = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_IPV4]              = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_IPV6]              = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_ICMP]              = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_UDP]               = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_PTP2]              = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_PTP2_SIGNALING]    = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_PTP2_ANNOUNCE]     = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_ANALYZER]          = PTP2_LOG_ERROR,
    [PTP2_LOG_PACKET_ASSEMBLER]         = PTP2_LOG_ERROR,
    [PTP2_LOG_PING_TABLE]               = PTP2_LOG_ERROR,
    [PTP2_LOG_ARP_TABLE]                = PTP2_LOG_ERROR,
    [PTP2_LOG_NODE_TABLE]               = PTP2_LOG_ERROR,
    [PTP2_LOG_SHADOW_TABLE]             = PTP2_LOG_ERROR,
    [PTP2_LOG_PROFILE]                  = PTP2_LOG_ERROR,
    [PTP2_LOG_BMCA]                     = PTP2_LOG_ERROR,
    [PTP2_LOG_TOD]                      = PTP2_LOG_ERROR,
    [PTP2_LOG_DATASET_DEFAULT]          = PTP2_LOG_ERROR,
    [PTP2_LOG_DATASET_CURRENT]          = PTP2_LOG_ERROR,
    [PTP2_LOG_DATASET_PARENT]           = PTP2_LOG_ERROR,
    [PTP2_LOG_DATASET_TIMEPROP]         = PTP2_LOG_ERROR,
    [PTP2_LOG_DATASET_PORT]             = PTP2_LOG_ERROR,
    [PTP2_LOG_DATASET_FOREIGN_MASTER]   = PTP2_LOG_ERROR,
    [PTP2_LOG_SPI_MASTER]               = PTP2_LOG_ERROR,
    [PTP2_LOG_SPI_SLAVE]                = PTP2_LOG_ERROR,
    [PTP2_LOG_PPS_PLL]                  = PTP2_LOG_ERROR
};

const char *PTP2_LOG_CATEGORY_STRING[] = {
    [PTP2_LOG_MASTER]                   = "[MASTER           ]",
    [PTP2_LOG_LOG]                      = "[LOG              ]",
    [PTP2_LOG_HAL_ENET]                 = "[HAL ENET         ]",
    [PTP2_LOG_HAL_TIMER]                = "[HAL TIMER        ]",
    [PTP2_LOG_HAL_PTP_TIME]             = "[HAL PTP TIME     ]",
    [PTP2_LOG_HAL_SLAVEMGM]             = "[HAL SLAVEMGM     ]",
    [PTP2_LOG_HAL_SYSCONF]              = "[HAL SYSCONF      ]",
    [PTP2_LOG_HAL_TOD]                  = "[HAL TOD          ]",
    [PTP2_LOG_HAL_ESMC]                 = "[HAL ESMC         ]",
    [PTP2_LOG_FSM]                      = "[FSM              ]",
    [PTP2_LOG_PORT]                     = "[PORT             ]",
    [PTP2_LOG_TASK]                     = "[TASK             ]",
    [PTP2_LOG_TASK_QUEUE]               = "[TASK QUEUE       ]",
    [PTP2_LOG_PACKET_ETHERNET]          = "[PACKET ETHERNET  ]",
    [PTP2_LOG_PACKET_ARP]               = "[PACKET ARP       ]",
    [PTP2_LOG_PACKET_IPV4]              = "[PACKET IPv4      ]",
    [PTP2_LOG_PACKET_IPV6]              = "[PACKET IPv6      ]",
    [PTP2_LOG_PACKET_ICMP]              = "[PACKET ICMP      ]",
    [PTP2_LOG_PACKET_UDP]               = "[PACKET UDP       ]",
    [PTP2_LOG_PACKET_PTP2]              = "[PACKET PTP2      ]",
    [PTP2_LOG_PACKET_PTP2_SIGNALING]    = "[PACKET PTP2 SIGNA]",
    [PTP2_LOG_PACKET_PTP2_ANNOUNCE]     = "[PACKET PTP2 ANNOU]",
    [PTP2_LOG_PACKET_ANALYZER]          = "[PACKET ANALYZER  ]",
    [PTP2_LOG_PACKET_ASSEMBLER]         = "[PACKET ASSEMBLER ]",
    [PTP2_LOG_PING_TABLE]               = "[PING TABLE       ]",
    [PTP2_LOG_ARP_TABLE]                = "[ARP TABLE        ]",
    [PTP2_LOG_NODE_TABLE]               = "[NODE TABLE       ]",
    [PTP2_LOG_SHADOW_TABLE]             = "[SHADOW TABLE     ]",
    [PTP2_LOG_PROFILE]                  = "[PTP PROFILE      ]",
    [PTP2_LOG_BMCA]                     = "[BMCA             ]",
    [PTP2_LOG_TOD]                      = "[TOD              ]",
    [PTP2_LOG_DATASET_DEFAULT]          = "[DATASET DEFAULT  ]",
    [PTP2_LOG_DATASET_CURRENT]          = "[DATASET CURRENT  ]",
    [PTP2_LOG_DATASET_PARENT]           = "[DATASET PARENT   ]",
    [PTP2_LOG_DATASET_TIMEPROP]         = "[DATASET TIMEPROP ]",
    [PTP2_LOG_DATASET_PORT]             = "[DATASET PORT     ]",
    [PTP2_LOG_DATASET_FOREIGN_MASTER]   = "[DATASET FOREIGN M]",
    [PTP2_LOG_SPI_MASTER]               = "[SPI MASTER       ]",
    [PTP2_LOG_SPI_SLAVE]                = "[SPI SLAVE        ]",
    [PTP2_LOG_PPS_PLL]                  = "[PPS PLL          ]"
};

const char *PTP2_LOG_LEVEL_STRING[] = {
    [PTP2_LOG_ERROR]                    = "[ERROR  ] ",
    [PTP2_LOG_WARNING]                  = "[WARN   ] ",
    [PTP2_LOG_INFO]                     = "[INFO   ] ",
    [PTP2_LOG_DEBUG]                    = "[DEBUG  ] ",
    [PTP2_LOG_VERBOSE]                  = "[VERBOSE] "
};

void
ptp2_log_init()
{
    ptp2_log                                                    = ptp2_default_log();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_MASTER]                    = ptp2_default_log_level_master();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_LOG]                       = ptp2_default_log_level_log();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_HAL_ENET]                  = ptp2_default_log_level_hal_enet();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_HAL_TIMER]                 = ptp2_default_log_level_hal_timer();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_HAL_PTP_TIME]              = ptp2_default_log_level_hal_ptp_time();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_HAL_SLAVEMGM]              = ptp2_default_log_level_hal_slavemgm();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_HAL_SYSCONF]               = ptp2_default_log_level_hal_sysconf();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_HAL_TOD]                   = ptp2_default_log_level_hal_tod();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_HAL_ESMC]                  = ptp2_default_log_level_hal_esmc();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_FSM]                       = ptp2_default_log_level_fsm();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PORT]                      = ptp2_default_log_level_port();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_TASK]                      = ptp2_default_log_level_task();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_TASK_QUEUE]                = ptp2_default_log_level_task_queue();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_ETHERNET]           = ptp2_default_log_level_packet_ethernet();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_ARP]                = ptp2_default_log_level_packet_arp();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_IPV4]               = ptp2_default_log_level_packet_ipv4();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_IPV6]               = ptp2_default_log_level_packet_ipv6();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_ICMP]               = ptp2_default_log_level_packet_icmp();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_UDP]                = ptp2_default_log_level_packet_udp();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_PTP2]               = ptp2_default_log_level_packet_ptp2();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_PTP2_SIGNALING]     = ptp2_default_log_level_packet_ptp2_signaling();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_PTP2_ANNOUNCE]      = ptp2_default_log_level_packet_ptp2_announce();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_ANALYZER]           = ptp2_default_log_level_packet_analyzer();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PACKET_ASSEMBLER]          = ptp2_default_log_level_packet_assembler();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PING_TABLE]                = ptp2_default_log_level_ping_table();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_ARP_TABLE]                 = ptp2_default_log_level_arp_table();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_NODE_TABLE]                = ptp2_default_log_level_node_table();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_SHADOW_TABLE]              = ptp2_default_log_level_shadow_table();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PROFILE]                   = ptp2_default_log_level_profile();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_BMCA]                      = ptp2_default_log_level_bmca();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_TOD]                       = ptp2_default_log_level_tod();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_DATASET_DEFAULT]           = ptp2_default_log_level_dataset_default();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_DATASET_CURRENT]           = ptp2_default_log_level_dataset_current();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_DATASET_PARENT]            = ptp2_default_log_level_dataset_parent();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_DATASET_TIMEPROP]          = ptp2_default_log_level_dataset_timeprop();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_DATASET_PORT]              = ptp2_default_log_level_dataset_port();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_DATASET_FOREIGN_MASTER]    = ptp2_default_log_level_dataset_foreign_master();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_SPI_MASTER]                = ptp2_default_log_level_spi_master();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_SPI_SLAVE]                 = ptp2_default_log_level_spi_slave();
    PTP2_LOG_CATEGORY_LEVEL[PTP2_LOG_PPS_PLL]                   = ptp2_default_log_level_pps_pll();
}

/*** MESSAGES ****************************************************************/

#if !PTP2_LOG_TIME_MSEC_HEX

/**
 * Get time from the system-clock and calculate time information
 *
 * @param now           reference to a date structure
 */
static void ptp2_log_date(ptp2_log_date_t *now)
{
    //critical_section_enter();
    uint32_t sys_msec = interval_timer_hal_get_second_fraction();
    uint32_t sys_sec  = interval_timer_hal_get_seconds();
    //critical_section_leave();
    
    now->day  = sys_sec   / (60 * 60 * 24);
    sys_sec  -= now->day  * (60 * 60 * 24);
    now->hour = sys_sec   / (60 * 60);
    sys_sec  -= now->hour * (60 * 60);
    now->min  = sys_sec   / (60);
    sys_sec  -= now->min  * (60);

    now->sec  = sys_sec;
    now->msec = sys_msec;
}

#endif

/**
 * Print header information like time and category
 *
 * @param category      list of categories, see ptp2_log.h
 * @param level         list of levels, see ptp2_log.h
 */
void
ptp2_log_print_header(ptp2_log_category_t category, ptp2_log_level_t level)
{
    
#if PTP2_LOG_TIME_MSEC_HEX
    critical_section_enter();
    uint32_t time_hex = interval_timer_hal_get_milliseconds();
    critical_section_leave();
    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "[%08" PRIx32 "]", time_hex);
#else
    ptp2_log_date_t     now;

    ptp2_log_date(&now);
    
    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "[%04" PRIu8 " %02" PRIu8 ":%02" PRIu8 ":%02" PRIu8 ".%03" PRIu8 "]", now.day, now.hour, now.min, now.sec, now.msec);
#endif

    PTP2_LOG_HEADER_CATEGORY(category);
    PTP2_LOG_HEADER_LEVEL(level);
}


void
ptp2_log_print(const char *format, ...)
{   
    va_list             args;
    
    va_start(args, format);
    PTP2_LOG_VPRINTF(PTP2_LOG_STREAM, format, args);
    PTP2_LOG_FLUSH(PTP2_LOG_STREAM);
    va_end(args);
}

void
ptp2_log_println(const char *format, ...)
{
    va_list             args;
    
    va_start(args, format);
    PTP2_LOG_VPRINTF(PTP2_LOG_STREAM, format, args);
    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "\n");
    PTP2_LOG_FLUSH(PTP2_LOG_STREAM);
    va_end(args);
}

void
ptp2_log_append(const char *format, ...)
{
    va_list             args;
    
    va_start(args, format);
    PTP2_LOG_VPRINTF(PTP2_LOG_STREAM, format, args);
    PTP2_LOG_FLUSH(PTP2_LOG_STREAM);
    va_end(args);
}

void
ptp2_log_appendln(const char *format, ...)
{
    va_list             args;
    
    va_start(args, format);
    PTP2_LOG_VPRINTF(PTP2_LOG_STREAM, format, args);
    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "\n");
    PTP2_LOG_FLUSH(PTP2_LOG_STREAM);
    va_end(args);
}


void
ptp2_log_char_stream(const char *stream, const uint32_t len)
{
    /*      ________________________
     *     |   |   |   |   |   |    |
     *     | 0 | x | F | F | _ | \0 |
     *     |___|___|___|___|___|____|
     *       0   1   2   3   4   5
     */
    uint32_t    idx;
    char        buffer[16];                                         /* hex string + NUL-character */

    snprintf(buffer, sizeof(buffer), " (len=%02" PRIu32 ") ", len);
    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, buffer);                       /* without NUL-character! */

    for (idx = 0; idx < len; idx++) {
        snprintf(buffer, 6 /* see comment */, "%02" PRIx8 " ", (uint8_t) stream[idx]);
        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, buffer);                   /* without NUL-character! */
    }

    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "\n");
}

/*** TO BIT FIELD ************************************************************/

void
ptp2_log_bit8(const uint8_t value, const uint8_t mask, uint8_t *str)
{
    uint8_t idx;
    uint8_t num;
    uint8_t bit;

    for (bit = (1 << 7), num = 0, idx = 0; bit > 0; bit >>= 1, num++, idx++) {

        if (num != 0 && num % 4 == 0) {
            str[idx++] = ' ';
        }

        if (mask & bit) {
            str[idx] = (value & bit) ? '1' : '0';
        } else {
            str[idx] = '.';
        }
    }
    str[idx] = '\0';
}

void
ptp2_log_bit16(const uint16_t value, const uint16_t mask, uint8_t *str)
{
    uint8_t idx;
    uint8_t num;
    uint16_t bit;

    for (bit = (1 << 15), num = 0, idx = 0; bit > 0; bit >>= 1, num++, idx++) {

        if (num != 0 && num % 4 == 0) {
            str[idx++] = ' ';
        }

        if (mask & bit) {
            str[idx] = (value & bit) ? '1' : '0';
        } else {
            str[idx] = '.';
        }
    }
    str[idx] = '\0';
}

void
ptp2_log_bit32(const uint32_t value, const uint32_t mask, uint8_t *str)
{
    uint8_t idx;
    uint8_t num;
    uint32_t bit;

    for (bit = (1 << 31), num = 0, idx = 0; bit > 0; bit >>= 1, num++, idx++) {

        if (num != 0 && num % 4 == 0) {
            str[idx++] = ' ';
        }

        if (mask & bit) {
            str[idx] = (value & bit) ? '1' : '0';
        } else {
            str[idx] = '.';
        }
    }
    str[idx] = '\0';
}

/*** TO STRING ***************************************************************/

/**
 *
 *   5    2  2  2     = 15
 * _____ __:__:__\0
 *
 */
void
ptp2_log_time(uint32_t seconds, uint8_t *str)
{
    uint32_t days;
    uint32_t hours;
    uint32_t minutes;

    days      = seconds   / (60 * 60 * 24);
    seconds  -= days      * (60 * 60 * 24);
    hours     = seconds   / (60 * 60);
    seconds  -= hours     * (60 * 60);
    minutes   = seconds   / (60);
    seconds  -= minutes   * (60);

                                             /*    days          hours   :     minutes :     seconds */
    snprintf((char *) str, PTP2_LOG_MAC_LEN, "%05" PRIu32 " %02" PRIu32 ":%02" PRIu32 ":%02" PRIu32, days, hours, minutes, seconds);
}

//void
//ptp2_log_mac(const mac_address_t *mac, uint8_t *str)
//{
//    snprintf((char *) str, PTP2_LOG_MAC_LEN, "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8,
//                                             mac->addr[0], mac->addr[1], mac->addr[2],
//                                             mac->addr[3], mac->addr[4], mac->addr[5]);
//}

//void
//ptp2_log_clock_identity(const ptp2_clock_identity_t *clock_identity, uint8_t *str)
//{
//    snprintf((char *) str, PTP2_LOG_CLOCK_IDENTITY_LEN, "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8,
//                                                        clock_identity->raw[0], clock_identity->raw[1], clock_identity->raw[2],
//                                                        clock_identity->raw[3], clock_identity->raw[4], clock_identity->raw[5],
//                                                        clock_identity->raw[6], clock_identity->raw[7]);
//}
//
//void
//ptp2_log_ipv4(const ipv4_address_t *ipv4, uint8_t *str)
//{
//    snprintf((char *) str, PTP2_LOG_IPV4_LEN, "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8 "", ipv4->addr[0],
//                                                             ipv4->addr[1],
//                                                             ipv4->addr[2],
//                                                             ipv4->addr[3]);
//}
//
//void
//ptp2_log_ipv6(const ipv6_address_t *ipv6, uint8_t *str)
//{
//    static const uint8_t    WIDTH = 4;      /* 16-bit, WIDTH=1: 4-bit */
//    uint16_t                i;
//    uint16_t                j;
//    uint8_t                 chr[WIDTH];
//    uint16_t                len = 0;
//    bool                    padding;
//
//    /* iterate over 8 blocks */
//    for (i = 0; i < IPV6_ADDRESS_HW_LEN; i++) {
//        /* IPv6 block is zero */
//        if (ipv6->addr16[i] == 0) {
//            str[len++] = '0';
//
//        /* IPv6 block is _NOT_ zero */
//        } else {
//            num2hexstr(ntohs(ipv6->addr16[i]), chr, WIDTH);
//            padding = true;
//            for (j = 0; j < WIDTH; j++) {
//                /* don't use leading zeros */
//                if (padding) {
//                    if (chr[j] != '0') {
//                        padding = false;
//                    } else {
//                        continue;
//                    }
//                }
//                str[len++] = chr[j];
//            }
//        }
//        str[len++] = ':';
//    }
//    str[--len] = '\0';
//}

//void
//ptp2_log_eui48(const eui48_t *eui48, uint8_t *str)
//{
//    snprintf((char *) str, PTP2_LOG_EUI48_LEN, "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8,
//                                               eui48->raw[0], eui48->raw[1], eui48->raw[2],
//                                               eui48->raw[3], eui48->raw[4], eui48->raw[5]);
//}

/**
 * Converts a 32-bit number (unsigned integer) to an ASCII character-arry
 * WITHOUT the NUL terminator
 *
 * @param num           32-bit number to be converted
 * @param chr           an already allocated reference to a fixed length character-array
 * @param len           length of the character-array
 */
static void
num2hexstr(uint32_t num, uint8_t *chr, size_t len)
{
    const static uint8_t HEXADECIMAL_LOWER[] = "0123456789abcdef";
    
    uint8_t    *reverse = &(chr[len]);
    
    while (len) {
        *--reverse = HEXADECIMAL_LOWER[num & 0x0f];
        num >>= 4;
        len--;
    }
}

/*** PACKETS *****************************************************************/

//void
//ptp2_log_raw_packet(raw_packet_t *raw_packet)
//{
//    uint32_t i;
//    uint32_t j;
//
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "raw packet (size = %u)\n", raw_packet->len);
//
//    // for every character in the data-array
//    for (i = 0; i < raw_packet->len ; i++) {
//
//        // if one line of hex printing is complete...
//        if (i != 0 && i % 16 == 0) {
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "         ");
//
//            for (j = i - 16; j < i; j++) {
//
//                // if its a number or alphabet
//                if (raw_packet->data[j] >= 32 && raw_packet->data[j] <= 128) {
//                    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "%c", (unsigned char) raw_packet->data[j]);
//
//                // otherwise print a dot
//                } else {
//                    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, ".");
//                }
//            }
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "\n");
//        }
//
//        if (i % 8 == 0) {
//            if (i % 16 == 0) {
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   ");
//           } else {
//               PTP2_LOG_PRINTF(PTP2_LOG_STREAM, " ");
//           }
//        }
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, " %02" PRIX8, raw_packet->data[i]);
//
//        // print the last spaces
//        if (i == raw_packet->len - 1) {
//
//            // extra spaces
//            for ( j = 0; j < 15 - i % 16; j++) {
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   ");
//            }
//
//            // add extra space between the two 8-byte blocks
//            if (15 - i % 16 >= 8) {
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, " ");
//            }
//
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "         ");
//
//            for ( j = i - i % 16; j <= i; j++) {
//                if (raw_packet->data[j] >= 32 && raw_packet->data[j] <= 128) {
//                    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "%c", (unsigned char) raw_packet->data[j]);
//                } else {
//                    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, ".");
//                }
//            }
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "\n");
//        }
//    }
//}
//
//void
//ptp2_log_packet(const packet_t *packet)
//{
//    packet_type_t filter = 0x00000001;
//
//    /* only log not ignored packets */
//    if (!(packet->info.type & PACKET_TYPE_IGNORE)) {
//        while (filter != 0) {
//            if (filter & packet->info.type) {
//                switch (filter) {
//                    case PACKET_TYPE_ETHERNET:          ptp2_log_ethernet_header        (ETHERNET_PACKET(packet));          break;
//                    case PACKET_TYPE_ARP:               ptp2_log_arp_packet             (ARP_PACKET(packet));               break;
//                    case PACKET_TYPE_IPV4:              ptp2_log_ipv4_header            (IP_PACKET(packet));                break;
//                    case PACKET_TYPE_IPV6:              ptp2_log_ipv6_header            (IP_PACKET(packet));                break;
//                    case PACKET_TYPE_ICMP:              ptp2_log_icmp_header            (ICMP_PACKET(packet));              break;
//                    case PACKET_TYPE_UDP:               ptp2_log_udp_header             (UDP_PACKET(packet));               break;
//                    case PACKET_TYPE_PTP2:              ptp2_log_ptp2_header            (PTP2_PACKET(packet));              break;
//                    case PACKET_TYPE_PTP2_SIGNALING:    ptp2_log_ptp2_signaling_header  (PTP2_SIGNALING_PACKET(packet));    break;
//                    case PACKET_TYPE_PTP2_ANNOUNCE:     ptp2_log_ptp2_announce_header   (PTP2_ANNOUNCE_PACKET(packet));     break;
//                    default:                                                                                                break;
//                }
//            }
//            filter = filter << 1;
//        }
//    }
//}
//
//void
//ptp2_log_ethernet_header(const ethernet_packet_t *ether_packet)
//{
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "Ethernet\n");
//
//    if (ether_packet->info.type & PACKET_TYPE_ETHERNET) {
//        PTP2_LOG_MAC(&(ether_packet->dest), dest_str);
//        PTP2_LOG_MAC(&(ether_packet->src),  src_str);
//
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Destination MAC                    %s\n",                                    dest_str);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Source MAC                         %s\n",                                    src_str);
//
//        if (ether_packet->type == ETHERTYPE_VLAN) {
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Tag Protocol Identifier (TPID)     %-15s (0x%04" PRIx16 ")\n",           ptp2_log_ether_type(ether_packet->type), ether_packet->type);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-VLAN                               0x%04" PRIx16 "\n",                   ether_packet->vlan.tci);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "     |-Priority       (PCP)             0x%02" PRIx8 "            (%u)\n",    ether_packet->vlan.pcp, ether_packet->vlan.pcp);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "     |-Drop Indicator (DEI)             %-15s (0x%02x)\n",                    ether_packet->vlan.dei ? "set" : "no set", ether_packet->vlan.dei);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "     |-Identifier     (VID)             0x%04" PRIx16 "          (%u)\n",     ether_packet->vlan.vid, ether_packet->vlan.vid);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "     |-Type                             %-15s (0x%04" PRIx16 ")\n",           ptp2_log_ether_type(ether_packet->vlan.type), ether_packet->vlan.type);
//        } else {
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Type                               %-15s (0x%04" PRIx16 ")\n",           ptp2_log_ether_type(ether_packet->type), ether_packet->type);
//        }
//    } else {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in Ethernet format\n");
//    }
//}

//void
//ptp2_log_arp_packet(const arp_packet_t *arp_packet)
//{
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "ARP\n");
//
//    if (arp_packet->info.type & PACKET_TYPE_ARP) {
//        PTP2_LOG_MAC(&(arp_packet->sha),  sha_str);
//        PTP2_LOG_MAC(&(arp_packet->tha),  tha_str);
//
//        PTP2_LOG_IPV4(&(arp_packet->spa), spa_str);
//        PTP2_LOG_IPV4(&(arp_packet->tpa), tpa_str);
//
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Hardware type (HTYPE)              %-15s (0x%04" PRIx16 ")\n", arp_packet->htype == ARP_HTYPE_ETHERNET ? "Ethernet" : "unknow", arp_packet->htype);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Protocol type (PTYPE)              %-15s (0x%04" PRIx16 ")\n", arp_packet->ptype == ARP_PTYPE_IPV4     ? "IPv4"     : "unknow", arp_packet->ptype);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Hardware address length (HLEN)     %-15u (0x%02" PRIx8  ")\n", arp_packet->hlen, arp_packet->hlen);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Protocol address length (PLEN)     %-15u (0x%02" PRIx8  ")\n", arp_packet->plen, arp_packet->plen);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Operation (OPER)                   %-15s (0x%04" PRIx16 ")\n", ptp2_log_arp_oper(arp_packet->oper), arp_packet->oper);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Sender hardware address (SHA)      %-15s\n",                   sha_str);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Sender protocol address (SPA)      %-15s (0x%08" PRIx32 ")\n", spa_str, arp_packet->spa.addr32);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Target hardware address (THA)      %-15s\n",                   tha_str);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Target protocol address (TPA)      %-15s (0x%08" PRIx32 ")\n", tpa_str, arp_packet->tpa.addr32);
//    } else {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in ARP format\n");
//    }
//}

//void
//ptp2_log_icmp_header(const icmp_packet_t *icmp_packet)
//{
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "ICMP Header\n");
//
//    if (icmp_packet->info.type & PACKET_TYPE_ICMP) {
//
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Type                               %-2"   PRId8  "\n", icmp_packet->type);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Code                               %-2"   PRIu8  "\n", icmp_packet->code);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Checksum                           0x%04" PRIx16 "\n", icmp_packet->checksum);
//        if (icmp_packet->type == ICMP_TYPE_ECHO_REQUEST || icmp_packet->type == ICMP_TYPE_ECHO_REPLY) {
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-%s\n",                                                                        ptp2_log_icmp_type_code(icmp_packet->type, icmp_packet->code));
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Identifier                      0x%04" PRIx16 "          (%" PRIu16 ")\n", icmp_packet->echo.id, icmp_packet->echo.id);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Sequence Number                 0x%04" PRIx16 "          (%" PRIu16 ")\n", icmp_packet->echo.seqno, icmp_packet->echo.seqno);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Data                            length: %-3u\n",                           icmp_packet->echo.len);
//        }
//
//    } else {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in ICMP format\n");
//    }
//}

//void
//ptp2_log_ipv4_header(const ip_packet_t *ipv4_packet)
//{
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "IPv4 Header\n");
//
//    if (ipv4_packet->info.type & PACKET_TYPE_IPV4) {
//        const ipv4_header_t    *ipv4_header = &(ipv4_packet->ipv4);
//
//        PTP2_LOG_IPV4(&(ipv4_header->src),  src_str);
//        PTP2_LOG_IPV4(&(ipv4_header->dest), dest_str);
//
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-IP Version                         %"     PRIu8 "\n",                            ipv4_header->version);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-IP Header Length                   %"     PRIu8 " dwords or %" PRIu8 " bytes\n", ipv4_header->ihl, ipv4_header->ihl * 4);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Differentiated Service             0x%02" PRIx8 "\n",                            ipv4_header->dscp);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-IP Total Length                    %"     PRIu16 " bytes\n",                     ipv4_header->len);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Identification                     0x%04" PRIx16 "          (%" PRIu16 ")\n",    ipv4_header->id, ipv4_header->id);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Dont Fragment Field                %-15s (0x%02" PRIx8 ")\n",                    ipv4_header->dont_fragment ? "set" : "no set", ipv4_header->dont_fragment);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-More Fragment Field                %-15s (0x%02" PRIx8 ")\n",                    ipv4_header->more_fragments ? "set" : "no set", ipv4_header->more_fragments);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Fragment Offset                    0x%04" PRIx16 "          (%u)\n",             ipv4_header->fragment_offset, ipv4_header->fragment_offset);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-TTL                                %"     PRIu8 "\n",                            ipv4_header->ttl);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Protocol                           %-15s (%"     PRIu8 ")\n",                    ptp2_log_ipv4_protocol(ipv4_header->protocol), ipv4_header->protocol);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Checksum                           0x%04" PRIx16 "          (%" PRIu16 ")\n",    ipv4_header->checksum, ipv4_header->checksum);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Source IP                          %-15s (0x%08" PRIx32 ")\n",                   src_str, ipv4_header->src.addr32);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Destination IP                     %-15s (0x%08" PRIx32 ")\n",                   dest_str, ipv4_header->dest.addr32);
//
//    } else {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in IPv4 format\n");
//    }
//}

//void
//ptp2_log_ipv6_header(const ip_packet_t *ipv6_packet)
//{
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "IPv6 Header\n");
//
//    if (ipv6_packet->info.type & PACKET_TYPE_IPV6) {
//
//    } else if (ipv6_packet->info.type & PACKET_TYPE_IPV6) {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in IPv6 format\n");
//    }
//}

//void
//ptp2_log_udp_header(const udp_packet_t *udp_packet)
//{
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "UDP Header\n");
//    if (udp_packet->info.type & PACKET_TYPE_UDP) {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Source Port                        %-15s (%" PRIu16 ")\n",               ptp2_log_ip_port(udp_packet->src_port), udp_packet->src_port);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Destination Port                   %-15s (%" PRIu16 ")\n",               ptp2_log_ip_port(udp_packet->dest_port), udp_packet->dest_port);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-UDP Length                         %"        PRIu16 " Bytes\n",          udp_packet->len);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-UDP Checksum                       0x%04"    PRIx16 "          (%u)\n",  udp_packet->checksum, udp_packet->checksum);
//    } else {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in UDP format\n");
//    }
//}

//void
//ptp2_log_ptp2_header(const ptp2_packet_t *ptp2_packet)
//{
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "PTP2 Header\n");
//    if (ptp2_packet->info.type & PACKET_TYPE_PTP2) {
//        PTP2_LOG_BIT8(ptp2_packet->msg_raw, 0xf0, transport_str);
//        PTP2_LOG_BIT8(ptp2_packet->msg_raw, 0x0f, msg_type_str);
//        PTP2_LOG_BIT8(ptp2_packet->version, 0x0f, version_str);
//
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0100, alternate_master_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0200, two_step_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0400, unicast_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x2000, ptp_profile_spec1_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x4000, ptp_profile_spec2_str);
//
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0001, leap61_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0002, leap59_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0004, utc_offset_valid_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0008, ptp_timescale_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0010, time_traceable_str);
//        PTP2_LOG_BIT16(ptp2_packet->flags, 0x0020, frequency_traceable_str);
//
//        PTP2_LOG_CLOCK_IDENTITY(&(ptp2_packet->src_port_identity.clock_identity), clock_identity_str);
//
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Transport Specific      %s  0x%02" PRIx8 "\n",                                   transport_str, ptp2_packet->transport);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Message Type            %s  0x%02" PRIx8 "            %s\n",                               msg_type_str,  ptp2_packet->msg_type, ptp2_log_message_type(ptp2_packet->msg_type));
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-PTP Version             %s  %-2"   PRIu8 "              (0x%02" PRIx8 ")\n",     version_str,   ptp2_packet->version,  ptp2_packet->version);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Message Length                     %-5" PRIu16 "           (0x%04" PRIx16 ")\n", ptp2_packet->msg_len, ptp2_packet->msg_len);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Domain Number                      %-3" PRIu8 "             (0x%02" PRIx8 ")\n", ptp2_packet->domain_number, ptp2_packet->domain_number);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Flag Field                         %-5" PRIu16 "           (0x%04" PRIx16 ")\n", ptp2_packet->flags, ptp2_packet->flags);
//
//        if (ptp2_packet->msg_type == PTP2_MESSAGE_TYPE_ANNOUNCE  || ptp2_packet->msg_type == PTP2_MESSAGE_TYPE_SYNC || ptp2_packet->msg_type == PTP2_MESSAGE_TYPE_FOLLOW_UP || ptp2_packet->msg_type == PTP2_MESSAGE_TYPE_DELAY_RESP) {
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Alternate Master                %-7s         (%s)\n", ptp2_packet->flags & 0x0100 ? "set" : "not set", alternate_master_str);
//        }
//
//        if (ptp2_packet->msg_type == PTP2_MESSAGE_TYPE_SYNC || ptp2_packet->msg_type == PTP2_MESSAGE_TYPE_DELAY_RESP) {
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Two Step                        %-7s         (%s)\n", ptp2_packet->flags & 0x0200 ? "set" : "not set", two_step_str);
//        }
//
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Unicast                         %-7s         (%s)\n", ptp2_packet->flags & 0x0400 ? "set" : "not set", unicast_str);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-PTP Profile Specific 1          %-7s         (%s)\n", ptp2_packet->flags & 0x2000 ? "set" : "not set", ptp_profile_spec1_str);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-PTP Profile Specific 2          %-7s         (%s)\n", ptp2_packet->flags & 0x4000 ? "set" : "not set", ptp_profile_spec2_str);
//
//        if (ptp2_packet->msg_type == PTP2_MESSAGE_TYPE_ANNOUNCE) {
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Leap 61                         %-7s         (%s)\n", ptp2_packet->flags & 0x0001 ? "set" : "not set", leap61_str);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Leap 59                         %-7s         (%s)\n", ptp2_packet->flags & 0x0002 ? "set" : "not set", leap59_str);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-UTC Offset Valid                %-7s         (%s)\n", ptp2_packet->flags & 0x0004 ? "set" : "not set", utc_offset_valid_str);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-PTP Timescale                   %-7s         (%s)\n", ptp2_packet->flags & 0x0008 ? "set" : "not set", ptp_timescale_str);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Time Traceable                  %-7s         (%s)\n", ptp2_packet->flags & 0x0010 ? "set" : "not set", time_traceable_str);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Frequency Traceable             %-7s         (%s)\n", ptp2_packet->flags & 0x0020 ? "set" : "not set", frequency_traceable_str);
//        }
//
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Source Clock Identity              %s\n",                                        clock_identity_str);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Source Port Number                 %-5" PRIu16 "           (0x%04" PRIx16 ")\n", ptp2_packet->src_port_identity.port_number, ptp2_packet->src_port_identity.port_number);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Sequence Id                        %-5" PRIu16 "           (0x%04" PRIx16 ")\n", ptp2_packet->seq_id,            ptp2_packet->seq_id);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Control Field                      %-3" PRIu8 "             (0x%02" PRIx8 ")\n", ptp2_packet->control,           ptp2_packet->control);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Log Message Interval               %-3" PRIu8 "             (0x%02" PRIx8 ")\n", ptp2_packet->log_msg_interval,  ptp2_packet->log_msg_interval);
//    } else {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in PTP2 format\n");
//    }
//}
//
//void
//ptp2_log_ptp2_signaling_header(const ptp2_signaling_packet_t *ptp2_signaling_packet)
//{
//    double period;
//    double rate;
//
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "PTP2 Signaling Header\n");
//    if (ptp2_signaling_packet->info.type & PACKET_TYPE_PTP2_SIGNALING) {
//        PTP2_LOG_CLOCK_IDENTITY(&(ptp2_signaling_packet->target_port_identity.clock_identity), clock_identity_str);
//
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Target Clock Identity              %s\n",                                            clock_identity_str);
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-Target Port Number                 %-5" PRIu16 "           (0x%04" PRIx16 ")\n",     ptp2_signaling_packet->target_port_identity.port_number, ptp2_signaling_packet->target_port_identity.port_number);
//
//        for (int idx = 0; idx < ptp2_signaling_packet->num_tlv; idx++) {
//
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-TLV %u\n", idx + 1);
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Type                            0x%04" PRIx16 "          %s\n",               ptp2_signaling_packet->tlv[idx].type, ptp2_log_tlv_type(ptp2_signaling_packet->tlv[idx].type));
//            PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Length                          0x%04" PRIx16 "          %" PRIu16 "\n",      ptp2_signaling_packet->tlv[idx].len,  ptp2_signaling_packet->tlv[idx].len);
//            /* request unicast transmission */
//            if (ptp2_signaling_packet->tlv[idx].type == PTP2_TLV_TYPE_REQUEST_UNICAST_TRANSMISSION) {
//                period = pow(2, ptp2_signaling_packet->tlv[idx].request_unicast.log_period);
//                rate   = 1 / period;
//
//                PTP2_LOG_BIT8(ptp2_signaling_packet->tlv[idx].request_unicast.msg.raw, 0xf0, msg_type_str);
//                PTP2_LOG_TIME(ptp2_signaling_packet->tlv[idx].request_unicast.duration, duration_str);
//
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Message Type         %s  0x%02" PRIx8 "            %s\n",                 msg_type_str, ptp2_signaling_packet->tlv[idx].request_unicast.msg.type,    ptp2_log_message_type(ptp2_signaling_packet->tlv[idx].request_unicast.msg.type));
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Log Inter Message Period        0x%02" PRIx8 "            %" PRId8 "\n",  (uint8_t) ptp2_signaling_packet->tlv[idx].request_unicast.log_period, ptp2_signaling_packet->tlv[idx].request_unicast.log_period);
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "         |-Period                                       every %lg second\n",      period);
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "         |-Rate                                         %lg %s/sec \n",           rate, rate == 1.0f ? "packet" : "packets");
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Duration Field                  0x%08" PRIx32 "      %s\n",               ptp2_signaling_packet->tlv[idx].request_unicast.duration, duration_str);
//
//            /* grant unicast transmission */
//            } else if (ptp2_signaling_packet->tlv[idx].type == PTP2_TLV_TYPE_GRANT_UNICAST_TRANSMISSION) {
//                period = pow(2, ptp2_signaling_packet->tlv[idx].grant_unicast.log_period);
//                rate   = 1 / period;
//
//                PTP2_LOG_BIT8(ptp2_signaling_packet->tlv[idx].grant_unicast.msg.raw, 0xf0, msg_type_str);
//                PTP2_LOG_TIME(ptp2_signaling_packet->tlv[idx].grant_unicast.duration, duration_str);
//                PTP2_LOG_BIT8(ptp2_signaling_packet->tlv[idx].grant_unicast.renewal.raw, 0x01,renewal_str);
//
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Message Type         %s  0x%02" PRIx8 "            %s\n",                 msg_type_str, ptp2_signaling_packet->tlv[idx].grant_unicast.msg.type,    ptp2_log_message_type(ptp2_signaling_packet->tlv[idx].grant_unicast.msg.type));
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Log Inter Message Period        0x%02" PRIx8 "            %" PRId8 "\n",  (uint8_t) ptp2_signaling_packet->tlv[idx].grant_unicast.log_period, ptp2_signaling_packet->tlv[idx].grant_unicast.log_period);
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "         |-Period                                       every %lg second\n",      period);
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "         |-Rate                                         %lg %s/sec \n",           rate, rate == 1.0f ? "packet" : "packets");
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Duration Field                  0x%08" PRIx32 "      %s\n",               ptp2_signaling_packet->tlv[idx].grant_unicast.duration, duration_str);
//                PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "      |-Renewal Invited                 %-7s         (%s)\n",                     ptp2_signaling_packet->tlv[idx].grant_unicast.renewal.flag ? "set" : "not set", renewal_str);
//
//            /* cancel unicast transmission */
//            } else if (ptp2_signaling_packet->tlv[idx].type == PTP2_TLV_TYPE_CANCEL_UNICAST_TRANSMISSION) {
//
//
//            } else if (ptp2_signaling_packet->tlv[idx].type == PTP2_TLV_TYPE_ACK_CANCEL_UNICAST_TRANSMISSION) {
//
//            }
//        }
//    } else {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in PTP2 Signaling format\n");
//    }
//}
//
//void
//ptp2_log_ptp2_announce_header(const ptp2_announce_packet_t *ptp2_announce_packet)
//{
//    PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "PTP2 Announce Header\n");
//    if (ptp2_announce_packet->info.type & PACKET_TYPE_PTP2_ANNOUNCE) {
//    } else {
//        PTP2_LOG_PRINTF(PTP2_LOG_STREAM, "   |-not in PTP2 Announce format\n");
//    }
//}
//
///**
// * Not implemented!
// */
//const char *
//ptp2_log_packet_type(packet_type_t packet_type)
//{
//    packet_type_t filter = 0x80000000;
//    while (filter != 0) {
//        filter = filter >> 1;
//        if (filter & packet_type) {
//            switch (filter) {
//                case PACKET_TYPE_ETHERNET:                  return "ethernet";
//                default:                                    return "not defined";
//            }
//        }
//    }
//
//    return "not defined";
//}
//
//const char*
//ptp2_log_node_address_type(const ptp2_address_type_t type)
//{
//    switch (type) {
//        case PTP2_ADDRESS_LAYER2:   return "layer2";
//        case PTP2_ADDRESS_IPV4:     return "IPv4";
//        case PTP2_ADDRESS_IPV6:     return "IPv6";
//        default:                    return "unknow";
//    }
//}
//
//const char*
//ptp2_log_ether_type(const uint16_t ether_type)
//{
//    switch (ether_type) {
//        case ETHERTYPE_IPV4:        return "IPv4";
//        case ETHERTYPE_IPV6:        return "IPv6";
//        case ETHERTYPE_ARP:         return "ARP";
//        case ETHERTYPE_VLAN:        return "VLAN";
//        case ETHERTYPE_PTP2:        return "PTPv2";
//        default:                    return "unknow";
//    }
//}
//
//const char *
//ptp2_log_arp_oper(const uint16_t oper)
//{
//    switch (oper) {
//        case ARP_OPER_REQUEST:          return "ARP Request";
//        case ARP_OPER_RESPONSE:         return "ARP Response";
//        default:                        return "Unknow";
//    }
//}
//
//const char *
//ptp2_log_icmp_type_code(const uint16_t type, const uint16_t code)
//{
//    switch (type) {
//        case ICMP_TYPE_ECHO_REQUEST:    return "ICMP Echo Request";
//        case ICMP_TYPE_ECHO_REPLY:      return "ICMP Echo Reply";
//        default:                        return "unknow";
//    }
//}
//
//const char *
//ptp2_log_ipv4_protocol(const uint8_t ipv4_protocol)
//{
//    switch (ipv4_protocol) {
//        case IPV4_PROTOCOL_TCP:     return "TCP";
//        case IPV4_PROTOCOL_UDP:     return "UDP";
//        case IPV4_PROTOCOL_ICMP:    return "ICMP";
//        default:                    return "unknow";
//    }
//}
//
//const char *
//ptp2_log_ipv6_protocol(const uint8_t ipv6_protocol)
//{
//    switch (ipv6_protocol) {
//        case IPV6_PROTOCOL_TCP:     return "TCP";
//        case IPV6_PROTOCOL_UDP:     return "UDP";
//        case IPV6_PROTOCOL_ICMP:    return "ICMP";
//        default:                    return "unknow";
//    }
//}
//
//const char*
//ptp2_log_ip_port(const uint16_t port)
//{
//    switch (port) {
//        case PORT_PTP2_EVENT:       return "PTPv2 Event";
//        case PORT_PTP2_GENERAL:     return "PTPv2 General";
//        default:                    return "unknow";
//    }
//}
//
//const char *
//ptp2_log_message_type(uint8_t msg_type)
//{
//    switch (msg_type) {
//        case PTP2_MESSAGE_TYPE_SYNC:                        return "Sync";
//        case PTP2_MESSAGE_TYPE_DELAY_REQ:                   return "Delay Request";
//        case PTP2_MESSAGE_TYPE_PDELAY_REQ:                  return "Peer-Delay Request";
//        case PTP2_MESSAGE_TYPE_PDELAY_RESP:                 return "Peer-Delay Response";
//        case PTP2_MESSAGE_TYPE_FOLLOW_UP:                   return "Follow Up";
//        case PTP2_MESSAGE_TYPE_DELAY_RESP:                  return "Delay Response";
//        case PTP2_MESSAGE_TYPE_PDELAY_RESP_FOLLOW_UP:       return "Peer-Delay Response Follow Up";
//        case PTP2_MESSAGE_TYPE_ANNOUNCE:                    return "Announce";
//        case PTP2_MESSAGE_TYPE_SIGNALING:                   return "Signaling";
//        case PTP2_MESSAGE_TYPE_MANAGEMENT:                  return "Management";
//        default:                                            return "Unknow";
//    }
//}
//
//const char *
//ptp2_log_tlv_type(uint16_t tlv_type)
//{
//    switch (tlv_type) {
//        case PTP2_TLV_TYPE_MANAGEMENT:                      return "Management";
//        case PTP2_TLV_TYPE_MANAGEMENT_ERROR_STATUS:         return "Management Error Status";
//        case PTP2_TLV_TYPE_ORGANIZATION_EXTENSION:          return "Organization Extension";
//        case PTP2_TLV_TYPE_REQUEST_UNICAST_TRANSMISSION:    return "Request Unicast Transmission";
//        case PTP2_TLV_TYPE_GRANT_UNICAST_TRANSMISSION:      return "Grant Unicast Transmission";
//        case PTP2_TLV_TYPE_CANCEL_UNICAST_TRANSMISSION:     return "Cancel Unicast Transmission";
//        case PTP2_TLV_TYPE_ACK_CANCEL_UNICAST_TRANSMISSION: return "Acknowledge Cancel Unicast Transmission";
//        case PTP2_TLV_TYPE_PATH_TRACE:                      return "Path Trace";
//        case PTP2_TLV_TYPE_ALTERNATE_TIME_OFFSET_INDICATOR: return "Alternate Time Offset Indicator";
//        case PTP2_TLV_TYPE_AUTHENTICATION:                  return "Authentication";
//        case PTP2_TLV_TYPE_AUTHENTICATION_CHALLENGE:        return "Authentication Challenge";
//        case PTP2_TLV_TYPE_SECURITY_ASSOCIATION_UPDATE:     return "Security Association Update";
//        case PTP2_TLV_TYPE_CUM_FREQ_SCALE_FACTOR_OFFSET:    return "Cumulative Frequency Scale Factor Offset";
//        default:                                            return "Unknow";
//    }
//}
//
//const char *
//ptp2_log_port_state(ptp2_port_state_t port_state)
//{
//    switch (port_state) {
//        case PTP2_PORT_STATE_NOT_DEFINED:                   return "NOT DEFINED";
//        case PTP2_PORT_STATE_INITIALIZING:                  return "INITIALIZING";
//        case PTP2_PORT_STATE_FAULTY:                        return "FAULTY";
//        case PTP2_PORT_STATE_DISABLED:                      return "DISABLED";
//        case PTP2_PORT_STATE_LISTENING:                     return "LISTENING";
//        case PTP2_PORT_STATE_PRE_MASTER:                    return "PRE-MASTER";
//        case PTP2_PORT_STATE_MASTER:                        return "MASTER";
//        case PTP2_PORT_STATE_PASSIVE:                       return "PASSIVE";
//        case PTP2_PORT_STATE_UNCALIBRATED:                  return "UNCALIBRATED";
//        case PTP2_PORT_STATE_SLAVE:                         return "SLAVE";
//        default:                                            return "UNKNOWN";
//    }
//}
//
//const char *
//ptp2_log_time_source(ptp2_time_source_t time_source)
//{
//    switch (time_source) {
//        case PTP2_TIME_SOURCE_ATOMIC_CLOCK:         return "ATOMIC_CLOCK";
//        case PTP2_TIME_SOURCE_GPS:                  return "GPS";
//        case PTP2_TIME_SOURCE_TERRESTRIAL_RADIO:    return "TERRESTRIAL_RADIO";
//        case PTP2_TIME_SOURCE_PTP:                  return "PTP";
//        case PTP2_TIME_SOURCE_NTP:                  return "NTP";
//        case PTP2_TIME_SOURCE_HAND_SET:             return "HAND_SET";
//        case PTP2_TIME_SOURCE_OTHER:                return "OTHER";
//        case PTP2_TIME_SOURCE_INTERNAL_OSCILLATOR:  return "INTERNAL_OSCILLATOR";
//        default:                                    return "UNKNOW";
//    }
//}
///**
// * 7.6.2.5 clockAccuracy
// */
//const char *
//ptp2_log_clock_accuracy(uint8_t clock_accuracy)
//{
//    if (clock_accuracy <= 0x1f || (clock_accuracy >= 0x32 && clock_accuracy <= 0x7f) || clock_accuracy == 0xff) {
//        return "reserved";
//    }
//
//    if (clock_accuracy >= 0x80 && clock_accuracy <= 0xfd) {
//        return "alternate profile";
//    }
//
//    switch (clock_accuracy) {
//        case 0x20: return "25 ns";
//        case 0x21: return "100 ns";
//        case 0x22: return "250 ns";
//        case 0x23: return "1 us";
//        case 0x24: return "2.5 us";
//        case 0x25: return "10 us";
//        case 0x26: return "25 us";
//        case 0x27: return "100 us";
//        case 0x28: return "250 us";
//        case 0x29: return "1 ms";
//        case 0x2a: return "2.5 ms";
//        case 0x2b: return "10 ms";
//        case 0x2c: return "25 ms";
//        case 0x2d: return "100 ms";
//        case 0x2e: return "250 ms";
//        case 0x2f: return "1 s";
//        case 0x30: return "10 s";
//        case 0x31: return "10 s";
//    }
//
//    return "unknow";
//}
//
//const char *
//ptp2_log_delay_mechanism(ptp2_delay_mechanism_t delay_mechanism)
//{
//    switch (delay_mechanism) {
//        case PTP2_DELAY_MECHANISM_E2E:      return "E2E";
//        case PTP2_DELAY_MECHANISM_P2P:      return "P2P";
//        case PTP2_DELAY_MECHANISM_DISABLED: return "disabled";
//    }
//
//    return "unknow";
//}
//
//const char *
//ptp2_log_node_address_state(ptp2_node_address_state_t state)
//{
//    switch (state) {
//        case PTP2_NODE_ADDRESS_STATE_INCOMPLETE:    return "INCOMPLETE";
//        case PTP2_NODE_ADDRESS_STATE_PROBE:         return "PROBE";
//        case PTP2_NODE_ADDRESS_STATE_REACHABLE:     return "REACHABLE";
//        case PTP2_NODE_ADDRESS_STATE_FAILED:        return "FAILED";
//        case PTP2_NODE_ADDRESS_STATE_STATIC:        return "STATIC";
//        default:                                    return "UNKNOW";
//    }
//}
